/**
 * 
 */
package org.estela.classifiers;

import java.util.logging.Logger;

import org.estela.ml.dataset.Attribute;
import org.estela.ml.dataset.DataSet;
import org.estela.ml.dataset.DiscreteAttribute;
import org.estela.ml.dataset.Instance;
import org.estela.ml.dataset.InvalidInstanceException;
import org.estela.util.MinMax;



/**
 * 
 * @version 1.00
 * @date Apr 23, 2006
 * @author <a href="mailto:akantek@nyse.com">Antonio Kantek</a>
 */
public abstract class AbstractClassifier implements Classifier {
	
	protected Logger _log = Logger.getLogger(getClass().getName());
	
	/** */
	protected Attribute[] attributes = null;
	
	/** Class attribute */
	protected Attribute classAttribute = null;

	/** */
	protected int classAttributeIndex;

	
	/**
	 * Default constructor. 
	 */
	public AbstractClassifier() {
	}
	
	/**
	 * 
	 * @param trainingSet
	 * @param classAttributeIndex
	 */
	protected void initClassifier(DataSet trainingSet, int classAttributeIndex) {
		assert trainingSet != null;
		assert classAttributeIndex >= 0;
		
		this.attributes = trainingSet.getAttributes();
		this.classAttribute = this.attributes[classAttributeIndex];
		this.classAttributeIndex = classAttributeIndex;
	}	

	/*
	 *  (non-Javadoc)
	 * @see classifiers.Classifier#classify(dataset.Instance)
	 */
	public double classify(Instance instance) throws InvalidInstanceException {
		assert instance != null;
		//check instance AND classAttribute with training set
		
		double[] distribution = this.distribution(instance);
		if (!this.classAttribute.isDiscrete()) {
			double max = MinMax.max(distribution);
			if (max > 0) {
				return max;
			} else {
				return Double.NaN;
			}
		}
		return distribution[0];
	}

	/*
	 *  (non-Javadoc)
	 * @see classifiers.Classifier#distribution(dataset.Instance)
	 */
	public double[] distribution(Instance instance) throws InvalidInstanceException {
		assert instance != null;
		//check instance AND classAttribute with training set
		
		double classification = this.classify(instance);
		double[] distribution;
		if (this.classAttribute.isDiscrete()) {
			if (classification == Double.NaN) {
				return new double[0]; 
			} else {
				DiscreteAttribute discreteClassAttribute = (DiscreteAttribute) this.classAttribute;
				String[] categories = discreteClassAttribute.getCategories();
				distribution = new double[ categories.length ];
				distribution[ (int)classification ] = 1d;
				return distribution;
			}
		}
		distribution = new double[]{classification};
		return distribution;
	}

	/* (non-Javadoc)
	 * @see classifiers.a#getAttributes()
	 */
	public Attribute[] getAttributes() {
		return attributes;
	}

	/* (non-Javadoc)
	 * @see classifiers.a#getClassAttribute()
	 */
	public Attribute getClassAttribute() {
		return classAttribute;
	}

	/* (non-Javadoc)
	 * @see classifiers.a#getClassAttributeIndex()
	 */
	public int getClassAttributeIndex() {
		return classAttributeIndex;
	}
}